﻿#include "FITKSimplifyMesh.h"
#include "FITK_Kernel/FITKCore/FITKVec3D.h"
#include "FITK_Interface/FITKInterfaceModel/FITKElementTri.h"

#include <OpenMesh/Tools/Decimater/DecimaterT.hh>
#include <OpenMesh/Tools/Decimater/ModQuadricT.hh>
#include <OpenMesh/Tools/Decimater/ModNormalDeviationT.hh>
#include <OpenMesh/Tools/Decimater/ModAspectRatioT.hh>

namespace Interface
{
    FITKSimplifyMesh::FITKSimplifyMesh()
    {
        //创建m_mesh对象
        m_mesh = new FITKPlateMesh;
        //创建Decimater对象，连接到m_mesh
        m_decimater = new OpenMesh::Decimater::DecimaterT<FITKPlateMesh>(*m_mesh);
    }

    FITKSimplifyMesh::~FITKSimplifyMesh()
    {
        if (m_mesh != nullptr) delete m_mesh;
    }

	QList<FITKSimplifyMeshPoint> FITKSimplifyMesh::getGeoPoint()
	{
		//记录网格顶点列表
		QList<FITKSimplifyMeshPoint> nodeList{};

		for (FITKPlateMesh::VertexIter v_it = m_mesh->vertices_begin(); v_it != m_mesh->vertices_end(); ++v_it)
		{
			FITKPlateMesh::VertexHandle vh = *v_it;
			FITKPlateMesh::Point point = m_mesh->point(vh);

			FITKSimplifyMeshPoint node{ vh.idx() + 1, { point[0], point[1], point[2] } };

			nodeList.append(node);
		}
		return nodeList;
	}

	QList<FITKSimplifyMeshEdge> FITKSimplifyMesh::getGeoBoundary()
	{
		//记录网格边界列表
		QList<FITKSimplifyMeshEdge> edgeBoundaryList{};
	
		for (FITKPlateMesh::EdgeIter edge_iter = m_mesh->edges_begin(); edge_iter != m_mesh->edges_end(); ++edge_iter)
		{
			if (!edge_iter->is_boundary()) continue;

			FITKPlateMesh::EdgeHandle eh = *edge_iter;

			//获取边的两个顶点
			FITKPlateMesh::VertexHandle vh1 = m_mesh->from_vertex_handle(m_mesh->halfedge_handle(*edge_iter, 0));
			FITKPlateMesh::VertexHandle vh2 = m_mesh->from_vertex_handle(m_mesh->halfedge_handle(*edge_iter, 1));

			FITKSimplifyMeshEdge edge{ eh.idx() + 1, {vh1.idx() + 1, vh2.idx() + 1 } };

			edgeBoundaryList.append(edge);
		}

		return edgeBoundaryList;
	}

	QList<FITKSimplifyMeshEdge> FITKSimplifyMesh::getGeoEdge()
	{
		//记录网格边列表
		QList<FITKSimplifyMeshEdge> edgeList{};
		
		for (FITKPlateMesh::EdgeIter edge_iter = m_mesh->edges_begin(); edge_iter != m_mesh->edges_end(); ++edge_iter)
		{
			FITKPlateMesh::EdgeHandle eh = *edge_iter;
			//获取边的两个顶点
			FITKPlateMesh::VertexHandle vh1 = m_mesh->from_vertex_handle(m_mesh->halfedge_handle(*edge_iter, 0));
			FITKPlateMesh::VertexHandle vh2 = m_mesh->from_vertex_handle(m_mesh->halfedge_handle(*edge_iter, 1));

			FITKSimplifyMeshEdge edge{ eh.idx() + 1, {vh1.idx() + 1, vh2.idx() + 1 } };
			edgeList.append(edge);
		}
		return edgeList;
	}

	QList<FITKSimplifyMeshFace> FITKSimplifyMesh::getGeoFace()
	{
		//记录网格单元链表
		QList<FITKSimplifyMeshFace> eleList{};

		//遍历网格面
		for (FITKPlateMesh::FaceIter f_it = m_mesh->faces_begin(); f_it != m_mesh->faces_end(); f_it++)
		{
			FITKPlateMesh::FaceHandle fh = *f_it;

			//记录当前面顶点id列表
			QList<int> edge_ids{};

			for (FITKPlateMesh::FaceHalfedgeIter fHe_iter = m_mesh->fh_begin(*f_it); fHe_iter != m_mesh->fh_end(*f_it); ++fHe_iter)
			{
				FITKPlateMesh::VertexHandle toV = fHe_iter->to();
				//获取边的数据
				FITKPlateMesh::EdgeHandle edge = m_mesh->edge_handle(*fHe_iter);
				FITKPlateMesh::VertexHandle vh2 = m_mesh->from_vertex_handle(m_mesh->halfedge_handle(edge, 1));
				if (toV.idx() == vh2.idx())
					edge_ids.append(edge.idx() + 1);
				else
					edge_ids.append(-(edge.idx() + 1));
			}

			FITKSimplifyMeshFace face{ fh.idx() + 1, {edge_ids[0],edge_ids[1],edge_ids[2]} };
			eleList.append(face);
		}
		return eleList;
	}

    QList<Core::FITKNode*> FITKSimplifyMesh::getMeshNode()
    {
        //记录网格顶点链表
        QList<Core::FITKNode*> nodeList{};

        //遍历网格点
        for (FITKPlateMesh::VertexIter v_it = m_mesh->vertices_begin(); v_it != m_mesh->vertices_end(); v_it++)
        {
            FITKPlateMesh::VertexHandle vh = *v_it;
            FITKPlateMesh::Point point = m_mesh->point(vh);

			Core::FITKNode* node = new Core::FITKNode(vh.idx() + 1, point[0], point[1], point[2]);

            nodeList.append(node);
        }
        return nodeList;
    }

    QList<Interface::FITKElementTri3*> FITKSimplifyMesh::getNodeElement()
    {
        //记录网格单元链表
        QList<Interface::FITKElementTri3*> eleList{};

        //遍历网格面
        for (FITKPlateMesh::FaceIter f_it = m_mesh->faces_begin(); f_it != m_mesh->faces_end(); f_it++)
        {
            FITKPlateMesh::FaceHandle fh = *f_it;
            
            //记录当前面顶点id列表
            QList<int> ele_ids{};

            //遍历面的顶点，添加顶点id
            for (FITKPlateMesh::FaceVertexIter fv_it = m_mesh->fv_iter(fh); fv_it.is_valid(); ++fv_it) 
            {
                FITKPlateMesh::VertexHandle vh = *fv_it;
				ele_ids.append(vh.idx() + 1);
            }

            Interface::FITKElementTri3* element = new Interface::FITKElementTri3();

            //设置顶点id
            element->setNodeID(ele_ids);

            eleList.append(element);
        }
        return eleList;
    }

    void FITKSimplifyMesh::simplifyMesh(size_t n_vertices, size_t n_faces)
    {
        //使用误差四边形简化网格模块
        OpenMesh::Decimater::ModQuadricT<FITKPlateMesh>::Handle hModQuadric;
        //在decimater上注册模块
        m_decimater->add(hModQuadric);

        //初始化decimater
        m_decimater->initialize();

        //执行网格简化
        m_decimater->decimate_to_faces(n_vertices, n_faces, false);

        //清理多余数据
        m_mesh->garbage_collection();
    }

    void FITKSimplifyMesh::setTriAspectRatio(double ratio)
    {
        //添加三角形长宽比保护模块
        OpenMesh::Decimater::ModAspectRatioT<FITKPlateMesh>::Handle hModAspectRatio;
        m_decimater->add(hModAspectRatio);

        //设置三角形长宽比
        OpenMesh::Decimater::ModAspectRatioT<FITKPlateMesh>& aspectRatio = m_decimater->module(hModAspectRatio);
        aspectRatio.set_aspect_ratio(ratio);
    }

    void FITKSimplifyMesh::lockBoundary()
    {
        //顶点请求启用状态标记
        m_mesh->request_vertex_status();

        //获取所有半边的迭代器
        FITKPlateMesh::HalfedgeIter he_it, he_end = m_mesh->halfedges_end();

        //如果半边为边界，则锁定半边对应的顶点
        for (he_it = m_mesh->halfedges_begin(); he_it != he_end; ++he_it)
        {
            if (!m_mesh->is_boundary(*he_it)) continue;

            m_mesh->status(m_mesh->to_vertex_handle(*he_it)).set_locked(true);
            m_mesh->status(m_mesh->from_vertex_handle(*he_it)).set_locked(true);
        }
    }

	void FITKSimplifyMesh::lockVertices(double angel1, double angel2)
	{
		//顶点请求启用状态标记
		m_mesh->request_vertex_status();

		//锁定特征顶点
		for (FITKPlateMesh::VertexIter v_it = m_mesh->vertices_begin(); v_it != m_mesh->vertices_end(); ++v_it)
		{
			if (!m_mesh->is_boundary(*v_it)) continue;

			FITKPlateMesh::VertexHandle vh = *v_it;
			FITKPlateMesh::Point point0 = m_mesh->point(vh);

			QList<OpenMesh::Vec3d> boundaryEdges{};

			//遍历边界点的相邻点
			for (FITKPlateMesh::VertexVertexIter vv_it = m_mesh->vv_iter(*v_it); vv_it.is_valid(); ++vv_it)
			{
				if (!m_mesh->is_boundary(*vv_it)) continue;
				
				FITKPlateMesh::VertexHandle vvh = *vv_it;
				FITKPlateMesh::Point point1 = m_mesh->point(vvh);

				OpenMesh::Vec3d edge = point1 - point0;

				boundaryEdges.append(edge);
			}

			//获取点相邻边的边界向量
			if (boundaryEdges.size() < 2) continue;
			OpenMesh::Vec3d e1 = boundaryEdges[0];
			OpenMesh::Vec3d e2 = boundaryEdges[1];

			//计算加角余弦值
			double e_cos = e1.dot(e2) / (e1.length() * e2.length());
			e_cos = std::max(-1.0, std::min(1.0, e_cos));

			//计算角度制角度
			double e_angel = acos(e_cos) * 180 / M_PI;

			//如果角度小于给定值，则锁定该点
			if (angel1 <= e_angel && e_angel <= angel2) m_mesh->status(v_it).set_locked(true);
		}
	}

    bool FITKSimplifyMesh::initPlateMesh(const QList<Core::FITKNode*>& meshPoints, const QList<Interface::FITKElementTri3*>& meshFaces)
    {
        if (meshPoints.empty() || meshFaces.empty()) return false;

        //对网格对象的数据清理
        m_mesh->clear();
        //记录网格点的容器
        std::vector<FITKPlateMesh::VertexHandle> vhandles{};
        //记录面顶点的容器
        std::vector<FITKPlateMesh::VertexHandle> face_vhandles{};
        //记录网格点的id
        QList<int> node_id{};

        //添加点
        for (QList<Core::FITKNode*>::const_iterator it = meshPoints.begin(); it != meshPoints.end(); it++)
        {
            FITKPlateMesh::Point m_point((*it)->x(), (*it)->y(), (*it)->z());
            //存储网格点的id
            node_id.append((*it)->getNodeID());
            vhandles.push_back(m_mesh->add_vertex(m_point));
        }

        //添加面
        for (QList<Interface::FITKElementTri3*>::const_iterator it = meshFaces.begin(); it != meshFaces.end(); ++it)
        {
            face_vhandles.clear();
            //判断是否是三角形拓扑单元类型
            if ((*it)->getEleType() != FITKModelEnum::FITKEleType::Tri3) return false;

            //获取点的id,加入到面顶点的容器中
            for (int i = 0; i < (*it)->getNodeCount(); i++)
            {
                //根据点的ID获取所在的索引
                int node_index = node_id.indexOf((*it)->getNodeID(i));
                if (node_index < 0 || node_index >= vhandles.size()) continue;
                face_vhandles.push_back(vhandles[node_index]);
            }
            //添加面
            if (face_vhandles.size() != 3) continue;

            m_mesh->add_face(face_vhandles);
        }
        return true;
    }
}